package top.someapp.dxf2dsvg;

import com.aspose.cad.Color;
import com.aspose.cad.ImageOptionsBase;
import com.aspose.cad.Size;
import com.aspose.cad.fileformats.cad.CadDrawTypeMode;
import com.aspose.cad.fileformats.cad.cadobjects.CadLayout;
import com.aspose.cad.imageoptions.CadRasterizationOptions;
import com.aspose.cad.imageoptions.JpegOptions;
import com.aspose.cad.imageoptions.SvgOptions;
import top.someapp.dxf2dsvg.base.ExportOptions;
import top.someapp.dxf2dsvg.cad.AutoCadFileLoader;
import top.someapp.dxf2dsvg.cad.AutoCadImage;

import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.*;

/**
 * @author zwz
 * Created on 2020-04-22
 */
public class CadImageExporter {
    private File cadFile;
    private File dirToSave;
    private AutoCadImage cadImage;
    private static final int MAX_PAGE_SIZE = 4096;
    private static final int PREFER_PAGE_SIZE = 1024;
    private static final int MIN_PAGE_SIZE = 512;

    public CadImageExporter(File cadFile) {
        this(cadFile, cadFile.getParentFile());
    }

    public CadImageExporter(File cadFile, File dirToSave) {
        this.cadFile = cadFile;
        this.dirToSave = dirToSave;
        if (!dirToSave.exists())
            dirToSave.mkdirs();
    }

    private CadRasterizationOptions loadAndSet() throws IOException {
        AutoCadFileLoader loader = AutoCadFileLoader.getLoader();
        if (cadImage == null)
            cadImage = loader.load(cadFile);
        // Create an instance of CadRasterizationOptions
        CadRasterizationOptions rasterOptions = new CadRasterizationOptions();

        // Set the layouts property
        Map<String, CadLayout> layoutMap = cadImage.getLayoutMap();
        if (!layoutMap.isEmpty()) {
            for (CadLayout layout : layoutMap.values()) {
                if (!layout.getLayoutName().equals("Model")) {
                    System.out.println("Using layout: " + layout.getLayoutName());
                    rasterOptions.setLayouts(new String[]{
                            layout.getLayoutName()
                    });
                    break;
                }
            }
        }

        // Set image width & height
        Size cadImageSize = cadImage.getSize();
        final int width = cadImageSize.getWidth();
        final int height = cadImageSize.getHeight();
        if (Math.max(width, height) > MAX_PAGE_SIZE) {
            double ratio = 1.0 * width / height;
            if (ratio >= 0.8 || ratio <= 1.2) { // 接近正方形的图纸
                rasterOptions.setPageWidth(PREFER_PAGE_SIZE);
                rasterOptions.setPageHeight(PREFER_PAGE_SIZE);
            } else if (width > height) {// 横向图纸
                rasterOptions.setPageWidth(MAX_PAGE_SIZE);
                rasterOptions.setPageHeight(Math.max(MIN_PAGE_SIZE, MAX_PAGE_SIZE * height / width));
            } else if (width < height) { // 纵向图纸
                rasterOptions.setPageHeight(MAX_PAGE_SIZE);
                rasterOptions.setPageWidth(Math.max(MIN_PAGE_SIZE, MAX_PAGE_SIZE * width / height));
            }
        } else {
            rasterOptions.setPageWidth(width);
            rasterOptions.setPageHeight(height);
        }

        // set colors
        rasterOptions.setBackgroundColor(Color.getLightGray());
        rasterOptions.setDrawType(CadDrawTypeMode.UseObjectColor);

        return rasterOptions;
    }

    private void exportLayer(String layer, CadRasterizationOptions rasterOptions, ImageOptionsBase options) throws IOException {
        System.out.println("Start export layer: " + layer);
        List<String> stringList = Arrays.asList(layer);
        rasterOptions.setLayers(stringList);
        options.setVectorRasterizationOptions(rasterOptions);
        File targetFile = new File(dirToSave, cadImage.getSimpleFileName() + "-layer-" + layer + ".svg");
        FileOutputStream out = new FileOutputStream(targetFile);
        if (options instanceof SvgOptions) {
            SvgOptions svgOptions = (SvgOptions) options;
            svgOptions.setCallback(new SvgCleaner(out, "layer-" + layer));
        }
        cadImage.writeTo(out, options);
        out.flush();
        out.close();
    }


    public void exportToJpg() throws IOException {
        CadRasterizationOptions rasterizationOptions = loadAndSet();
        String fileName = cadImage.getSimpleFileName() + ".jpg";
        JpegOptions options = new JpegOptions();
        options.setVectorRasterizationOptions(rasterizationOptions);
        cadImage.writeTo(new FileOutputStream(new File(dirToSave, fileName)), options);
    }

    private void loadAndConfig(CadRasterizationOptions rasterOptions, ExportOptions exportOptions) throws IOException {
        if (cadImage == null) {
            AutoCadFileLoader loader = AutoCadFileLoader.getLoader();
            cadImage = loader.load(cadFile);
        }

        // Set the layouts property
        Map<String, CadLayout> layoutMap = cadImage.getLayoutMap();
        if (!layoutMap.isEmpty()) {
            for (CadLayout layout : layoutMap.values()) {
                if (!layout.getLayoutName().equals("Model")) {
                    System.out.println("Using layout: " + layout.getLayoutName());
                    rasterOptions.setLayouts(new String[]{
                            layout.getLayoutName()
                    });
                    break;
                }
            }
        }

        // set colors
        rasterOptions.setBackgroundColor(Color.getLightGray());
        rasterOptions.setDrawType(CadDrawTypeMode.UseObjectColor);

        // Set image width & height
        Dimension exportSize = exportOptions.getSize();
        if (exportSize == null) {
            Size cadImageSize = cadImage.getSize();
            final int width = cadImageSize.getWidth();
            final int height = cadImageSize.getHeight();
            if (Math.max(width, height) > MAX_PAGE_SIZE) {
                double ratio = 1.0 * width / height;
                if (ratio >= 0.8 || ratio <= 1.2) { // 接近正方形的图纸
                    exportSize = new Dimension(PREFER_PAGE_SIZE, PREFER_PAGE_SIZE);
                } else if (width > height) {// 横向图纸
                    exportSize = new Dimension(MAX_PAGE_SIZE, Math.max(MIN_PAGE_SIZE, MAX_PAGE_SIZE * height / width));
                } else if (width < height) { // 纵向图纸
                    exportSize = new Dimension(Math.max(MIN_PAGE_SIZE, MAX_PAGE_SIZE * width / height), MAX_PAGE_SIZE);
                }
            } else {
                exportSize = new Dimension(width, height);
            }
        }
        rasterOptions.setPageWidth(exportSize.width);
        rasterOptions.setPageHeight(exportSize.height);
    }

    public void exportToSvg(ExportOptions exportOptions) throws IOException {
        CadRasterizationOptions rasterOptions = new CadRasterizationOptions();
        loadAndConfig(rasterOptions, exportOptions);
        List<String> layerNames = cadImage.getLayerNames();
        Set<String> targetLayers = new LinkedHashSet<>();
        if (exportOptions.isExportLayer0()) {
            targetLayers.add("0");
        }
        if (exportOptions.isUseInclude()) {
            if (exportOptions.getIncludes() == null || exportOptions.getIncludes().length > 0) {
                // include nothing!!
            } else {
                for (String layer : layerNames) {
                    if (contains(exportOptions.getIncludes(), layer)) {
                        targetLayers.add(layer);
                    }
                }
            }
        } else {
            if (exportOptions.getExcludes() == null || exportOptions.getExcludes().length == 0) {
                // exclude nothing
                targetLayers.addAll(layerNames);
            } else {
                for (String layer : layerNames) {
                    if (!contains(exportOptions.getExcludes(), layer)) {
                        targetLayers.add(layer);
                    }
                }
            }
        }
        if (targetLayers.isEmpty()) {
            targetLayers.addAll(layerNames);
        }
        if (ExportOptions.ONE_LAYER_ONE_FILE.equalsIgnoreCase(exportOptions.getLayerToSvg())) {
            exportLayerPerFile(targetLayers, rasterOptions, new SvgOptions());
        } else {
            exportLayersInOne(targetLayers, rasterOptions, new SvgOptions());
        }
    }

    private void exportLayerPerFile(
            Collection<String> layers, CadRasterizationOptions rasterOptions, ImageOptionsBase options)
            throws IOException {
        for (String layer : layers) {
            exportLayer(layer, rasterOptions, options);
        }
    }

    private void exportLayersInOne(
            Collection<String> layers, CadRasterizationOptions rasterOptions, ImageOptionsBase options)
            throws IOException {
        System.out.println("Start export " + layers.size() + " layers in one file.");
        List<String> layerList = new ArrayList<>(layers);
        rasterOptions.setLayers(layerList);
        options.setVectorRasterizationOptions(rasterOptions);
        File targetFile = new File(dirToSave, cadImage.getSimpleFileName() + ".svg");
        FileOutputStream out = new FileOutputStream(targetFile);
        if (options instanceof SvgOptions) {
            SvgOptions svgOptions = (SvgOptions) options;
            svgOptions.setCallback(new SvgCleaner(out, "layers-in-one"));
        }
        cadImage.writeTo(out, options);
        out.flush();
        out.close();
    }

    private static boolean contains(String[] includes, String layer) {
        for (String include : includes) {
            if (layer.equalsIgnoreCase(include))
                return true;
        }
        return false;
    }

}
